﻿/*
   Author: Tomer Paz
   games.com
   2007
*/
// the game controller class
package monopoly.GameController {

	import flash.display.DisplayObjectContainer;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.utils.Timer;
	import fl.controls.Button;
	import fl.controls.TextInput;
	import fl.events.ComponentEvent;
	import flash.utils.ByteArray;
	import monopoly.CMD.*;
	import monopoly.Player.*;
	import monopoly.Field.Field;
	import monopoly.GameBoard.GameBoard;
	import monopoly.GameBoard.GameBoardCollection;
	import monopoly.views.*;
	import monopoly.ServerBroadcast.*;
	import monopoly.IFS.iterators.IIterator;
	import monopoly.IFS.GLOBALS;
	import monopoly.GameController.Dialogs.*;
	import monopoly.GameController.Dialogs.Templates.*;
	import monopoly.chat.*;
	import monopoly.DBA.IDBClient;
	import monopoly.DBA.DBClient;
	import monopoly.Localization.*;
	import flash.utils.Endian;
//@TP - add support for Base64 - for chat messages:
	import monopoly.IFS.utils.com.dynamicflash.util.Base64;
	import flash.media.Sound;
	import flash.media.SoundChannel;

	
	public class GameController extends Sprite
		{
		/* public members */
		
		// shall be loaded from DB
		public static var NUM_OF_FIELDS:int = 0;	// TOTOAL number of fields!
		public static const NUM_OF_BOARDS = 2;		// number of VISIBLE boards!
				
		/* private members */	
		
		
		/* configuration */
		
		private var _ServerPort:int = 3456;						// should have been taken from Web server DB via PHP_AMF...
		private var _WebServerImagesURL:String;


		/* object members */
		
		private var _NetAgentCMDs:ICMD;
		private var _GameBoards:GameBoardCollection;			// created in Init + filled in BuildBoards()
		private var _GameBoardViews:GameBoardViewCollection;	// same
		private var _Players:PlayersCollection;					// created during Execution since taken from G.Server
		private var _MyPlayer:Player;							// just a reference to "my" player (this client)
		private var _chatClient:ChatClient;						// chat GUI Data object
		private var _serverBroadcast:ServerBroadcast;			// server broadcast GUI data object
		private var _DBClient:IDBClient;
		// we could go further and define yet another container class just for player-Views, but that's too excessive at this point:
		private var _PlayersViews:Array = new Array();
		private var _PlayersStatusView:PlayersStatusView;
		private var _VPanel:VPanel;
		private var _BottomPanel:BottomPanel;
		private var _Resign:ResignView;
		private var _GameActionSound:PayBuySellSound;
		private var _GameInfoViewer:GameInfoViewer;
		private var _myStrings:ILocalLanguage;
		
		/* IDs */
		
		private var _ClientID:uint;
		private var _ClientVersion:int;
		private var _GameID:uint;
//		private var _SessionID:uint;
		private var _myIP:String;
		private var _mySecretKey:String;
		
		/* working variables */
		
		// Map for Server command instructions VS action functions
		private var _ServerInstructionsMap:Object;
		
		private var _NumOfActivePlayers:int = 0;
		private var _RootSprite:Sprite;
		private var _PopupMessageHandler:PopupMessageHandler;
		private var _FirstTurnFlag:Boolean = true;
		private var _ShallPopDown:Boolean  = true;

		//constructor
		public function GameController(myIP:String, secretKey:String, ClientID:uint, ClientVersion:uint, GameID:uint, RootSprite:Sprite):void
			{
			_myIP			= myIP;
			_ClientID		= ClientID;
			_ClientVersion	= int(ClientVersion);
			_GameID			= GameID;
			_mySecretKey	= secretKey;
			
			_WebServerImagesURL = "http://" + GLOBALS.WebServerName;
			
			_GameBoards		= GameBoardCollection.getInstance();
			_GameBoardViews = GameBoardViewCollection.getInstance();
			
			/* load parameters from DB */
			
			_DBClient = DBClient.getInstance(GLOBALS.WebServerName, RootSprite);
			
			_RootSprite = RootSprite;
			
			/* add chat system */
			
			_chatClient = new ChatClient(_ClientID);
			_chatClient.addEventListener(ComponentEvent.ENTER, onOutgoingChatMessage);
			
			// moved to Game class
			//LoadDBInfo();
			}
					
		/* called from Game object */
		
		public function LoadDBInfo():void
			{
			_DBClient.addEventListener(Event.COMPLETE, onGameDataComplete);

			_DBClient.get_game_data(_GameID);

			}
		private function onGameDataComplete(e:Event):void
			{
			_DBClient.removeEventListener(Event.COMPLETE, onGameDataComplete);
				
			_DBClient.addEventListener(Event.COMPLETE, onBoardPropertiesComplete);
			_DBClient.get_properties_list(_GameID);
			}
			
		private function onBoardPropertiesComplete(e:Event)
			{
			_DBClient.removeEventListener(Event.COMPLETE, onBoardPropertiesComplete);
				
			/* Load Players data accordfing to current Game invitations */
			
			AddPlayers(_DBClient.game_data[0]["max_attendies"]);
			}
		
		/* Execute() shall be called from Game object to start managing the game - the "main" function */
		
		public function Execute():void
			{
			/* draw the first board view */

			// set the current active Board - and as consequence, the Board View. of-cousre board 0 at this point.
			// the rest 'will happen by itself' (event driven)
			if (_GameBoards.SetActiveBoard(0) == false)
				{
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_VIEW)
					trace("error: could not set Active Board to 0");
				return;
				}

			/* add players Views to first board view anyway... */

			for (var j:int = 0; j < _PlayersViews.length; j++)
					Sprite(_GameBoardViews.getChildAt(0)).addChild(_PlayersViews[j]);

			/* add Panels and Field Views */
			
			_VPanel		= new VPanel(this);
			_BottomPanel= new BottomPanel(this);
			
			/* add game info pane */
			
			_GameInfoViewer = new GameInfoViewer();
			_GameInfoViewer.name = BottomPanel.BPANEL_CENTER;
			_BottomPanel.addChild(_GameInfoViewer);
			
			// attach field views to Panel
			var fieldView:FieldView;
			var fieldVIter:IIterator = (_GameBoardViews.getChildAt(0) as GameBoardView).iterator();
			
			for (var i:int = 0; i < NUM_OF_FIELDS && fieldVIter.hasNext(); i++)
				{
				fieldView = fieldVIter.next() as FieldView;
				//_BottomPanel.addChild(fieldView.attachStatusToPanel());
				_GameInfoViewer.addChild(fieldView.attachStatusToPanel());
				
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_VIEW)
					trace("[GameController][Execute] Adding field StatusBox to Bottom Panel");
				}
			
			/* init language */
			
			_myStrings = LocalLanguage.getInstance();
			_myStrings.MyLang = _MyPlayer.LangID;
			
			/* setup connection (CMD socket) to game server */
			
			var CMDfactory:CMDFactory = new CMDFactory();
			
			/* CMD net agent is taking care of managing connection with server */
			
			_NetAgentCMDs = CMDfactory.getInstance(GLOBALS.ServerName, _ServerPort, _myIP, _mySecretKey);	// returns either RemoteCMD or LocalCMD instance
			_NetAgentCMDs.ClientID  = _ClientID;
//			_NetAgentCMDs.SessionID = _SessionID;
			
			/* Init the server instructions map */
			
			InitInstructionsMap();
									
			/* Catch protocol commands recieved over Socket from server */
			
			_NetAgentCMDs.addEventListener(CMDResponseEvent.RESPOND, onServerInstructions);

			/* layout componets */
			
			//_PopupMessageHandler = new PopupMessageHandler(_BottomPanel);
			_PopupMessageHandler = new PopupMessageHandler(_GameInfoViewer);
			
			_chatClient.name = BottomPanel.BPANEL_RIGHT;
			_BottomPanel.addChild(_chatClient);
			
			/* add server broadcast system */
			
			_serverBroadcast = new ServerBroadcast();
			_serverBroadcast.name = BottomPanel.BPANEL_LEFT;
			_BottomPanel.addChild(_serverBroadcast);
			
			/* add Players Status viewer */

			_PlayersStatusView = new PlayersStatusView(_Players, _RootSprite.width, _RootSprite.height, this.root.stage);
			_PlayersStatusView.setupStatusArea(_RootSprite.width, _RootSprite.height);	// overcome Flash stupid bug
			_PlayersStatusView.name = VPanel.RPANEL_UPPER;
			_VPanel.addChild(_PlayersStatusView);
			
			for each(var pview:PlayerView in _PlayersViews)
				{
				//_BottomPanel.addChild(pview.StatusBox);
				_GameInfoViewer.addChild(pview.StatusBox);
				}
			
			/* add resign button */
			
			_Resign = new ResignView(_RootSprite.root.stage);
			_Resign.name = VPanel.RPANEL_BOTTOM;
			_Resign.addEventListener(Event.COMPLETE, onResign);
			_VPanel.addChild(_Resign);
			_Resign.x = _Resign.x + _VPanel.width*0.7;
			_Resign.width = 80;
			
			_RootSprite.root.stage.stageFocusRect = true;
			
			/* add sound */
			
			_GameActionSound = new PayBuySellSound();
			}
		
		/* Boards builder */
		
		// uses the IFS created in GameBoard, GameBoardContainer, Board and Fields views, Players etc'
		private function BuildBoards():void	
			{
			var board:GameBoard;
			var boardView:GameBoardView;
			
			/* create X boards of size BOARD_SIZE each. create the GambeBoard Views */

			// this is the TOTAL # of fields!!
			NUM_OF_FIELDS = _DBClient.game_data[0]["board_sz"];
			
			_GameBoardViews.addEventListener(Event.COMPLETE, onBoardViewsComplete);
			_GameBoardViews.x = GLOBALS.VPANEL_WIDTH + GLOBALS.VPADDING;
			
			/* attach GambeBoardViews collection Sprite to this container display object (Sprite) */

			addChild( _GameBoardViews );

			for (var i:int = 1; i < NUM_OF_BOARDS; i++)
			    {
				board = new GameBoard(NUM_OF_FIELDS, GLOBALS.BOARD_WIDTH, GLOBALS.BOARD_HEIGHT, _WebServerImagesURL, 0);

				/* add the board to the boards collection */
				
				_GameBoards.addBoard(board);
				
				/* attach a board View to board data */
				
				boardView = new GameBoardView(board);
				
				/* add the board view to board view collection */
				
				_GameBoardViews.addBoardView(boardView);
				}			
				
			/* attach GameBoardViewCollection View instance as listener to GameBoardCollection Data instance */
				
			_GameBoardViews.GameBoardsCollection = _GameBoards;
			}
		
		private function onBoardViewsComplete(e:Event):void
			{
			_GameBoardViews.removeEventListener(Event.COMPLETE, onBoardViewsComplete);
			
			dispatchEvent(new Event(Event.COMPLETE)); 	// inform Game to trigger "Execute"
			}
			
		/* add players */
		
		private function AddPlayers(numOfPlayers:uint):void
			{
			_NumOfActivePlayers = numOfPlayers;
			
			/* create or get instance of players collection */
			
			_Players = PlayersCollection.getInstance();
			
			/* use opportunity to add Chat listener to Players container */
			
			_Players.addEventListener(Event.ADDED, _chatClient.onPlayerChange);
			_Players.addEventListener(Event.REMOVED, _chatClient.onPlayerChange);
			
			/* add players */

			_DBClient.addEventListener(Event.COMPLETE, onCompletePlayersData);
			
			_DBClient.get_players_data(_GameID);
			}
			
		private function onCompletePlayersData(e:Event):void
			{
			/* init players */
				
			for (var i:int=1; i <= _DBClient.players_data.length; i++)
				{
				var pname:String  = _DBClient.players_data[i-1]["user_name"];
				var player:Player = new Player(pname, _DBClient.players_data[i-1]["user_id"]);

				/* get specific User Info */
				
				player.Logo		 = _DBClient.players_data[i-1]["logo"];
				player.FirstName = _DBClient.players_data[i-1]["f_name"];
				player.LastName	 = _DBClient.players_data[i-1]["l_name"];
				player.Email	 = _DBClient.players_data[i-1]["email"];
				player.LangID	 = _DBClient.players_data[i-1]["lang_id"];
				player.Age		 = _DBClient.players_data[i-1]["age"];
				player.City		 = _DBClient.players_data[i-1]["adrs_city"];
				player.Country	 = _DBClient.players_data[i-1]["adrs_country"];
				player.Gender	 = _DBClient.players_data[i-1]["gender"];
				
				player.set_XY( (i == 1) ? 1:(i-1)*20, 0);
				
				player.Cash = _DBClient.game_data[0]["start_payment"];
				
				_Players.addPlayer(player);
				
				// add a view for player
				var playerView:PlayerView = new PlayerView(player);
				
				if (player.ID == _ClientID)
					{
					_MyPlayer = player;
					_MyPlayer.VisibleStatus = true;
					}
				else
					{	// per deicision about JOIN_RESPONSE 165 command (just to make sure...)
					player.VisibleStatus = false;
					}
				
				// add to my list
				_PlayersViews.push(playerView);
				}
				
			/* add NULL players for Empty slots */
			
			if (i < GLOBALS.MAX_NUM_PLAYERS)
				{
				for (i = i+1; i <= GLOBALS.MAX_NUM_PLAYERS; i++)
					{
					_Players.addPlayer(null);
					}
				}
				
			_DBClient.removeEventListener(Event.COMPLETE, onCompletePlayersData);
			// Done with players, build the entire boards data models and views
			BuildBoards();	
			}

		/* triggered when server sends STATUS with new player || when new player "Join" the room (160) */
		
		private function addPlayerToGame(player:Player):void
			{
			_Players.addPlayer(player);
			
			// add a view for player
			player.VisibleStatus = true;
			var playerView:PlayerView = new PlayerView(player);

			// add to my list
			_PlayersViews.push(playerView);
			// draw on board
			Sprite(_GameBoardViews.getChildAt(0)).addChild(playerView);
			}
			
	
		/* Server Instructions function map */
		
		private function InitInstructionsMap( ):void
			{
			/* onServerInstructions() will call these functions by reference */
			
			_ServerInstructionsMap = new Object( );
			_ServerInstructionsMap[ CMD.INTRO		] = sendINTRO;
			_ServerInstructionsMap[ CMD.ACCEPT		] = checkAuthorizationStatus;
		    _ServerInstructionsMap[ CMD.STATUS	 	] = onStatusRespond;
			_ServerInstructionsMap[ CMD.JOIN_RESPONSE ] = onServerJoinResponse;
			_ServerInstructionsMap[ CMD.CHAT		] = onIncomingChatMessage;
			_ServerInstructionsMap[ CMD.BROADCAST	] = onServerBroadcast;
			_ServerInstructionsMap[ CMD.ACTION_RES 	] = onClientActionResponse;		// server response to client request
			_ServerInstructionsMap[ CMD.ACTION_REQ 	] = onClientActionRequest;		// other player response to MyPlayer request (a.k.a "offer")

			_ServerInstructionsMap[ CMD.DISCONNECT	] = CMDdisconnect;
			}
		
		/* this function is a handler for Server Responses to Client commands (Dialogs) or just server commands */
		
		private function onServerInstructions(cmdResEvent:CMDResponseEvent):void
			{
			/* extract server respond (structure) and execute the mapped instructed (Action) function */
			
			var cmdResponse:CMDResponse = cmdResEvent.gCMDResponse;
			
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				{
				trace("[GameController][onServerInstructions] Value of CMD state is: " + _NetAgentCMDs.State);
				trace("[GameController][onServerInstructions] And CMD is: " + cmdResponse.Command);
				}
				
			/* Look up the processing function based on the command in the respond */
			
			var Cmd:uint;
			if ((cmdResponse.Command == CMD.DONE_MOVE) || (cmdResponse.Command == CMD.ACTION_PAY) ||(cmdResponse.Command == CMD.ACTION_BUY) || (cmdResponse.Command == CMD.ACTION_EXCHANGE) || 
						(cmdResponse.Command == CMD.ACTION_PARTNER) || (cmdResponse.Command == CMD.ACTION_SELL) || (cmdResponse.Command == CMD.ACTION_UPGRADE))
					{
					Cmd = CMD.ACTION_RES;
					}
				else if ((cmdResponse.Command == CMD.ACTION_SEL_RESP) || (cmdResponse.Command == CMD.ACTION_BUY_RESP) ||
						(cmdResponse.Command == CMD.ACTION_EXC_RESP) || (cmdResponse.Command == CMD.ACTION_PAR_RESP))
					{
					Cmd = CMD.ACTION_REQ;
					}
				else
					{
					Cmd = cmdResponse.Command;
					}

			var processFunc:Function = _ServerInstructionsMap[ Cmd ];
			
			/* call the mapped command function, providing it with Server respond arguments */
			
			processFunc(cmdResponse);
			}
			
		private function sendINTRO(cmdRes:CMDResponse):void
			{
			/* fill in the INTRO command values: Client_ID:Session_ID:INTRO:{Client_Version} */
						
			_NetAgentCMDs.sendINTRO(_ClientVersion, _GameID);
			}
		
		/* in response to AUTHORIZED state */
		
		private function checkAuthorizationStatus(cmdResponse):void
			{
			if (_NetAgentCMDs.Authorized == true)
				{
				_NetAgentCMDs.State = CMD.PLAYER_TYPE;
				
				/* now it is in GameController Mandate to start dialgos... */
				
				sendReadyCmd();
				}
			else
				{
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
					trace("[GameController][checkAuthorizationStatus] Server Not authorized this client. shall quit!");
				_NetAgentCMDs.State = CMD.DISCONNECT;
				}
			}
			
		/* in PLAYER_TYPE state */	
		
		private function sendReadyCmd():void
			{
			// need to add a timer to this place later, so if no decision has been made in ~15 seconds, automatically "View" will be chosen

			/* input dialog */

			var joinOrViewDialog:IDialog = new JoinViewStartDialogs(_myStrings.MsgJReady,
														  _myStrings.MsgJText,
														  _myStrings.DlgJVSJoin, _myStrings.DlgJVSView);
			
			/* listen for dialog client respond */
			
			joinOrViewDialog.addEventListener(Event.COMPLETE, onCmdDialogButtonClick);
			(joinOrViewDialog as Sprite).name = VPanel.RPANEL_MIDDLE;
			_VPanel.addChild(DisplayObject(joinOrViewDialog));
			}
		private function sendStartCmd():void
			{
			/* input from dialog shall be given here */
			
			// need to add a timer to this place later, so if no decision has been made in ~15 seconds, automatically "Start" will be chosen
			var startDialog:IDialog = new JoinViewStartDialogs(_myStrings.MsgJSReady,
														  _myStrings.MsgJSText,
														  _myStrings.DlgJVSStart, null);
			
			/* listen for dialog client respond */
			
			startDialog.addEventListener(Event.COMPLETE, onCmdDialogButtonClick);
			(startDialog as Sprite).name = VPanel.RPANEL_MIDDLE;
			_VPanel.addChild(startDialog as Sprite);
			}
			
		private function CMDdisconnect():void
			{
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("Someone asked to disconnect");
			_NetAgentCMDs.CMDdisconnect();
			}
		
		/* game timer event handlers */
		
		private function onGameTimer(event:TimerEvent):void
			{
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("[GameController][onGameTimer] onTimeEvent Handler: " + event);
			/* play some background sound in loop... */
			
			/* check some status 'running' flags ...(like maybe user would like to abort game) */
			}
		private function onGameTimerCompletion():void
			{
			/* this game time is over, Clean some resources before returning to Execute() noraml abortion */
			// delete( )...
			}
			
		/* specific event handlers for CMD commands and Dialogs */
		
		private function onCmdDialogButtonClick(e:Event):void
			{
			var dialog:IDialog = e.currentTarget as IDialog;
			var chosen_option:uint = dialog.chosenAction;
						
			switch (chosen_option)
				{
				case (JoinViewStartDialogs.ACTION_VIEW) :
					_NetAgentCMDs.ready(chosen_option);
					_PopupMessageHandler.popupMessageBox(null, null);
					break;
				case (JoinViewStartDialogs.ACTION_JOIN) :
					_NetAgentCMDs.ready(chosen_option);
					_PopupMessageHandler.popupMessageBox(null, null);
					_Resign.enableResign();
					_chatClient.Enable = true;
					break;
				case (JoinViewStartDialogs.ACTION_START) :
					_NetAgentCMDs.sendStart();
					_PopupMessageHandler.popupMessageBox(_myStrings.MsgJoinWait, null);
					break;
				}
			
			/* this command is done hence shutdown the BasicDialog */
		
			e.currentTarget.removeEventListener(Event.COMPLETE, onCmdDialogButtonClick);
			_VPanel.removeChild(Sprite(e.currentTarget));
			}
		
		
		/* handle server STATUS update report */
		
		private function onStatusRespond(cmdRes:CMDResponse):void
			{
			/* first remove WAIT message box */
			
			if (_ShallPopDown)
				_PopupMessageHandler.popdownMessageBox();
			_ShallPopDown = true;		// no matter what it was
			
			/* analyse the server status report and engage proper action */
			
			var contentBA:ByteArray = ByteArray(cmdRes.Content);
			
			var Status:int = contentBA.readInt();

			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("[GameController][OnStatusRespond] Status sub-CMD is: " + Status);
			
			if (CMD.STATUS_PLAY == Status)
				{
				_PlayersStatusView.change_status(_MyPlayer);
				
				if (_FirstTurnFlag == true)
					{
					_FirstTurnFlag = false;
					playerDialogBeforeDies(PlayDialog.TYPE_FIRST_MOVE);
					}
				else
					playerDialogBeforeDies(PlayDialog.TYPE_MOVE);
				}
			else if (CMD.STATUS_WAIT == Status)
				{
				var acid:uint		 = contentBA.readInt();
				
				var player:Player	 = SelectPlayerByID(acid);
				_PlayersStatusView.change_status(player); 
				
				/* popup WAIT message */
				
				_PopupMessageHandler.popupMessageBox(_myStrings.MsgJSWaitPlayer(player.Name), null);
				}
			else if (CMD.STATUS_UPDATE == Status)
				{
				UpdateStatus(cmdRes.Size, contentBA, Status);
				}
			else if (CMD.STATUS_DIES == Status)
				{
				var myPlayer_change_position:uint = _MyPlayer.CurrentPosition;
				
				UpdateStatus(cmdRes.Size, contentBA, Status);
				
				/* add dialog for Post-Move actions (+ "done move") here only if MyPlayer moved */
				
				if (myPlayer_change_position != _MyPlayer.CurrentPosition)
					{
					if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
						trace("[GameController][onStatusRespond][CMD.STATUS_DIES] I chagned position...");
					_NetAgentCMDs.done_move(_MyPlayer.CurrentPosition);
					
					if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
						trace("[GameController[[onStatusRespond][CMD.STATUS_DIES] Sent done_move. now need to bring up AfterDies dialog...");
					}
				}
			}

		/* parse Server STATUS Update Location+Properties for all players */
		
		private function UpdateStatus(ContentSize:uint, contentBA:ByteArray, Status:int):void
			{
			// "header":clientId:SessionId:Commad:content_sz
					
			var numOfPlayers:uint; // = _Players.getLength();
			var playerID:int;
			var player:Player;
			var i:int;

			if (CMD.STATUS_UPDATE == Status)
				{
				/* upadte Field/Property that changed */
				//|abid|upgrade_level|curr_cost|fee|status|owner| 
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
					trace("[GameController][UpdateStatus][182] start");
				
				var property_location:int 	= contentBA.readInt();		// == abid = absolute field ID
				var upgrade_level:int		= contentBA.readInt();
				var curr_cost:int			= contentBA.readInt();
				var fee:int					= contentBA.readInt();
				var fStatus:int				= contentBA.readInt();
				var ownerPid:int			= contentBA.readInt();

				UpdateProperty(property_location, upgrade_level, curr_cost, fee, fStatus, ownerPid);
				
				/* update players */
				//NumberOfPlayerUpdateRecords|   
				// array of records with players data: [|acid|new_position|cash_status|SizeOfName|Name| ...|acid|new_position|cash_status|SizeOfName|Name| ]
				numOfPlayers = contentBA.readInt();
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
					trace("[GameController][UpdateStatus][182] number of player: " + numOfPlayers);
					
				for (i = 0; i < numOfPlayers && contentBA.bytesAvailable; i++)
					{
					/* update player location */
					
					playerID	= contentBA.readInt();
					player		= (playerID == _MyPlayer.ID) ? _MyPlayer : SelectPlayerByID(playerID);

					if (null == player)
						{
						player = new Player(null, playerID);
						}

					player.CurrentPosition 	= contentBA.readInt();
					player.Cash	    		= contentBA.readInt();
					var sizeofName			= contentBA.readInt();
					var Name:String			= contentBA.readUTFBytes(sizeofName);
					
					/* Read UTF String work-around - Begin */
					
					var jj:int;
					for (jj = 1; jj <= 6; jj++)
						{
						contentBA.readInt();
						}
					/* Read UTF String work-around - End */
					
					if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
						{
						trace("[GameController][UpdateStatus][182] player ID: " + playerID);
						trace("[GameController][UpdateStatus][182] player position: " + player.CurrentPosition);
						trace("[GameController][UpdateStatus][182] player Name: " + Name);
						trace("[GameController][UpdateStatus][182] player CASH: " + player.Cash);
						}
					
					if (null == player.Name)
						{
						player.Name = Name;
						addPlayerToGame(player);
						}
						
					UpdatePlayerPosition(player);
					}
				}
			else if (CMD.STATUS_DIES == Status)
					{					
					numOfPlayers = _Players.getLength();
					
					for (i = 0; i < numOfPlayers && contentBA.bytesAvailable; i++)
						{
						playerID	= contentBA.readInt();
						player		= (playerID == _MyPlayer.ID) ? _MyPlayer : SelectPlayerByID(playerID);

						var dies1:int = contentBA.readInt();
						var dies2:int = contentBA.readInt();
						var sum:int = dies1 + dies2;
					
						if ((player.CurrentPosition + sum) > NUM_OF_FIELDS)
							{
							if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
								{
								trace("[GameController][UpdateStatus][CMD.STATUS_DIES] Old player position: " + player.CurrentPosition);
								trace("[GameController][UpdateStatus][CMD.STATUS_DIES] And Dies SUM = " + sum);
								}
							player.CurrentPosition = player.CurrentPosition + sum - NUM_OF_FIELDS;
							if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
								{
								trace("[GameController][UpdateStatus][CMD.STATUS_DIES] Number of fields is: " + NUM_OF_FIELDS);
								trace("[GameController][UpdateStatus][CMD.STATUS_DIES] New player position: " + player.CurrentPosition);
								}
							}
						else
							{
							player.CurrentPosition += sum;
							}
						UpdatePlayerPosition(player);
												
						// update status view
						_PlayersStatusView.diesResult = String(sum);
						}
					}
				}
		
		/* DB cordinate-based function to update a player location on board */
		
		private function UpdatePlayerPosition(player:Player):void
			{
			// move player view to new field view
			var board:GameBoard	  		= _GameBoards.ActiveBoard;
			var FieldIterator:IIterator = board.iterator();
			var field:Field;
			
			while (FieldIterator.hasNext())
				{
				field = Field(FieldIterator.next());

				if (field.PropertyID == player.CurrentPosition)
					{
					player.set_XY(field.X+15, field.Y);
					if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
						trace("[GameController][UpdatePlayerPosition] Player X: " + player.X + ", Player Y: " + player.Y);
					break;
					}
				}
			}

		
		/* update Field/Property data */

		private function UpdateProperty(p_location:int, upgrade_level:int, curr_cost:int, fee:int, fStatus:int, ownerPid:int):void
			{
			/* locate relevant Field - to adjust Property status */
				
			var field:Field = null;
			
			
			/* simple math for: on which board is this field (by abid = "p_location") ? */
			
			var tmpIndex:int   = Math.ceil(p_location / NUM_OF_FIELDS) - 1; // shift left due to board array start from Zero
			var boardIndex:int = (tmpIndex < 0) ? 0 : tmpIndex;
			
			if (_GameBoards.SetActiveBoard(boardIndex) != true)
				{
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
					trace("Error switching Active Board");
				return;
				}

			var FieldRelativePos:uint = p_location % NUM_OF_FIELDS;
			//trace("[UpdateProperty] Field Location is: " + p_location + ", while Relative Field location is: " + FieldRelativePos);
			
			field = getFieldbyID(FieldRelativePos);

			
			/* finally - update data */
			
			field.UpgradeLevel  = upgrade_level;
			field.Cost			= curr_cost;
			field.Fee			= fee;
			field.Status		= fStatus;
			// we do this one last since only this one dispatches the event 
			field.Owner = SelectPlayerByID(ownerPid);
			}
			
		/* on Sever Join Reponse */
		
		private function onServerJoinResponse(cmdRes:CMDResponse):void
			{
			var contentBA:ByteArray = cmdRes.Content as ByteArray;
			
			_PopupMessageHandler.popdownMessageBox();
			
			/* parse content */
			
			var NumOfPlayers:int	= contentBA.readInt();
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("[GameController][onServerJoinResponse]Players:" + NumOfPlayers);
				
			for (var i:int = 0; i < NumOfPlayers; i++)
				{
				var playerID:int    = contentBA.readInt();
				var nameSize:int	= contentBA.readInt();
				var plyrName:String = contentBA.readUTFBytes(nameSize);
				
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
					trace("[GameController][onServerJoinResponse]Player details:  Name=" + plyrName + " , ID=" + playerID);
				
				/* add player */
				
				var player:Player = (playerID == _MyPlayer.ID) ? _MyPlayer : SelectPlayerByID(playerID);
			
				/* add the player */

				if (null == player)
					{
					player = new Player(plyrName, playerID);
					player.Cash	= _MyPlayer.Cash;			// we can assume all players are equal at the beginning...
					addPlayerToGame(player);
					}
				else
					{
					player.VisibleStatus = true;
					}
				}
				
			/* time to offer "Start Game" */
			
			if (player == _MyPlayer) 
				{ 
				sendStartCmd(); 
				}
			}
			
		/* broadcast message handling */
		
		private function onServerBroadcast(cmdRes:CMDResponse):void
			{
			var contentBA:ByteArray = cmdRes.Content as ByteArray;
			
			/* parse content */
			
			var Type:int		= contentBA.readInt();
			var playerID:int    = contentBA.readInt();
			var Message:String  = contentBA.readUTFBytes(cmdRes.Size - GLOBALS.INT_SIZE*2);
			
			var player:Player = (playerID == _MyPlayer.ID) ? _MyPlayer : SelectPlayerByID(playerID);
			
			/* update icons and data */
			
			switch(Type) {
				case (CMD.BCAST_TYPE_JOIN) : 
					/* add the player *
					if (null == player)
						{
						player = new Player(null, playerID);
						player.Cash	= _MyPlayer.Cash;			// we can assume all players are equal at the beginning...
						addPlayerToGame(player);
						}
					else
						{
						player.VisibleStatus = true;
						}
					*/
					break;
				case (CMD.BCAST_TYPE_START) : 
					break;		// nothing for now, just print message at the end of function
				case (CMD.BCAST_TYPE_DISCON) : 
					//player.VisibleStatus = false;
					break;
				case (CMD.BCAST_TYPE_QUIT) : 
					//player.VisibleStatus = false;
					break;
				default : 
					if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)	
						trace("[GameController][onServerBroadcast] no Broadcast type chosen, defaulting to do Nothing");
				}
			
			
			/* update broadcast GUI */

			_serverBroadcast.WriteMessage(player.Name, Message);
			}
			
		/* chat handling functions */
		
		private function onIncomingChatMessage(cmdRes:CMDResponse):void
			{
			//@TPAZ - fix a bug with chat string 17.aug.08:
			var contentBA:ByteArray = cmdRes.Content as ByteArray;
			
			/* parse content */
			
			var SenderID:uint   = contentBA.readInt();
			var rcptID:uint		= contentBA.readInt();

			//var decoded:ByteArray = Base64.decodeToByteArray(contentBA.readObject());

//			var decoded:ByteArray = Base64.decodeToByteArray(contentBA.readUTF());
			var Message:String  = contentBA.readUTFBytes(cmdRes.Size-2*GLOBALS.INT_SIZE);
//			var Message:String	= decoded.readUTF();
			
			/* update chat GUI */

			var playerIter:IIterator = _Players.iterator();
			var player:Player;
			var SenderName:String;
			
			for (var i:uint = 0; playerIter.hasNext() && (player = Player(playerIter.next())); i++)
				{
				if (SenderID == player.ID)
					SenderName = player.Name;
				}
			
			/* write the message */
			
			_chatClient.WriteMessage(SenderName, SenderID, rcptID, Message);   // write message to Screen (sprite)
			}
			
		private function onOutgoingChatMessage(e:ComponentEvent)
			{
			if (e.type == ComponentEvent.ENTER && e.target is ChatClient)
				{
//				_NetAgentCMDs.chat(Base64.encode(_chatClient.MyMsg), _MyPlayer.ID);
				_NetAgentCMDs.chat(_chatClient.MyMsg, _MyPlayer.ID, _chatClient.ActiveChatPlayerID);
				}
			}
			
		
		/* Player Turn Decision-Dialogs */
			
		/* full play options dialog BEFORE Turn */
		
		private function playerDialogBeforeDies(type:uint):void
			{
			var playDialog = new PlayDialog(type, (_MyPlayer == (getFieldbyID(_MyPlayer.CurrentPosition).Owner)) ? true : false );
			playDialog.addEventListener(Event.COMPLETE, onPlayerDiesDecision);
			playDialog.name = VPanel.RPANEL_MIDDLE;
			_VPanel.addChild(playDialog);
			}
		
		// Before move decision (flow diagram 1)
		private function onPlayerDiesDecision(e:Event):void
			{
			var playDialog:PlayDialog = e.currentTarget as PlayDialog;
			
			switch (playDialog.chosenAction)
				{
				case (PlayDialog.ACTION_MOVE) :
					_NetAgentCMDs.throw_dies();
					_PopupMessageHandler.popupMessageBox(null, null);
					break;
				case (PlayDialog.ACTION_PROPERTIES) :
					pre_dies_property_actions_dialog();
					break;
				}
				
			e.currentTarget.removeEventListener(Event.COMPLETE, onPlayerDiesDecision);
			_VPanel.removeChild(e.currentTarget as Sprite);
			}
		// properties dialog before throw-dies (flow diagram 7)
		private function pre_dies_property_actions_dialog():void
			{
			var preDiesActionsDialog:PreDiesActionsDialog = new PreDiesActionsDialog(playerHasFullFieldGroup(_MyPlayer));
			preDiesActionsDialog.addEventListener(Event.COMPLETE, onPreDiesActions);
			preDiesActionsDialog.name = VPanel.RPANEL_MIDDLE;
			_VPanel.addChild(preDiesActionsDialog);
			}
			
		private function onPreDiesActions(e:Event):void
			{
			var preDiesActionsDialog:PreDiesActionsDialog = e.currentTarget as PreDiesActionsDialog;
			var field:Field = getFieldbyID(_MyPlayer.CurrentPosition);
			
			switch(preDiesActionsDialog.chosenAction)	
				{
				case (PreDiesActionsDialog.ACTION_SELL):				// Share/Sell my Property: to be enhanced in future to Any of my properties...
					var sellDialog:SellDialog = new SellDialog(field, _Players, _MyPlayer.ID);
					sellDialog.addEventListener(Event.COMPLETE, sellDialogComplete);
					sellDialog.name = VPanel.RPANEL_MIDDLE;
					_VPanel.addChild(sellDialog);
					break;
				case (PreDiesActionsDialog.ACTION_UPGRADE):				// Upgrade Property
					var upgradeDialog:UpgradeDialog = new UpgradeDialog(field);
					upgradeDialog.addEventListener(Event.COMPLETE, upgradeDialogComplete);
					upgradeDialog.loadDialog();
					upgradeDialog.name = VPanel.RPANEL_MIDDLE;
					_VPanel.addChild(upgradeDialog);
					break;
				case (PreDiesActionsDialog.ACTION_AUCTION):				// Auction my property: to be continued...
					var auctionDialog:AuctionDialog = new AuctionDialog(field, AuctionDialog.STATUS_AUCTION);
					auctionDialog.addEventListener(Event.COMPLETE, auctionDialogComplete);
					auctionDialog.name = VPanel.RPANEL_MIDDLE;
					_VPanel.addChild(auctionDialog);
					break;
				case (PreDiesActionsDialog.ACTION_MORTGAGE):			// Mortgage: to be continued...
					break;
				case (PreDiesActionsDialog.ACTION_RETURN):
					playerDialogBeforeDies(PlayDialog.TYPE_MOVE);
					break;
				}
				
			e.currentTarget.removeEventListener(Event.COMPLETE, onPreDiesActions);
			_VPanel.removeChild(e.currentTarget as Sprite);
			}
			
		private function sellDialogComplete(e:Event):void
			{
			var sellDialog:SellDialog = e.currentTarget as SellDialog;
			
			_NetAgentCMDs.ac_sell(sellDialog.Data[SellDialog.PLAYER_ID], sellDialog.Data[SellDialog.FIELD].PropertyID, sellDialog.Data[SellDialog.SELL_PRICE]);
			
			e.currentTarget.removeEventListener(Event.COMPLETE, sellDialogComplete);
			_VPanel.removeChild(e.currentTarget as Sprite);
			
			_PopupMessageHandler.popupMessageBox(_myStrings.MsgSellWait(SelectPlayerByID(sellDialog.Data[SellDialog.PLAYER_ID]).Name), null);
			}
		private function upgradeDialogComplete(e:Event):void
			{
			var upgradeDialog:UpgradeDialog = e.currentTarget as UpgradeDialog;
			
			e.currentTarget.removeEventListener(Event.COMPLETE, upgradeDialogComplete);
			if (_VPanel.contains(upgradeDialog))
				_VPanel.removeChild(upgradeDialog);	
			
			switch (upgradeDialog.chosenAction)
				{
				case (UpgradeDialog.ALREADY_MAX_LEVEL):
					_PopupMessageHandler.Timeout = 3000;
					_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
					_ShallPopDown = false;
					_PopupMessageHandler.popupMessageBox("Property Already at Maximum Level.\n You can't upgrade it further", pre_dies_property_actions_dialog);
					break;
				case (UpgradeDialog.NO_MONEY_TO_UPGRADE):
					_PopupMessageHandler.Timeout = 3000;
					_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
					_ShallPopDown = false;
					_PopupMessageHandler.popupMessageBox("Sorry, You can't upgrade. You do not have enough cash :(", pre_dies_property_actions_dialog);
					break;
				case (UpgradeDialog.PASS):
					pre_dies_property_actions_dialog();
					break;
				default:
					_PopupMessageHandler.popupMessageBox("Upgrading Property...", null);
					_NetAgentCMDs.ac_upgrade(upgradeDialog.Data.PropertyID, upgradeDialog.chosenAction);
				}
			}
		// on My Auction dialog complete (490 or 690)
		private function auctionDialogComplete(e:Event):void
			{
			var auctionDialog:AuctionDialog = e.currentTarget as AuctionDialog;
			
			_NetAgentCMDs.ac_auction(auctionDialog.field.PropertyID, int(auctionDialog.Data));
			
			e.currentTarget.removeEventListener(Event.COMPLETE, auctionDialogComplete);
			_VPanel.removeChild(e.currentTarget as Sprite);
			
			_ShallPopDown = true;
			if (AuctionDialog.STATUS_AUCTION == auctionDialog.Status)
				_PopupMessageHandler.popupMessageBox(_myStrings.MsgAucPlayersOffer, null);
			else
				_PopupMessageHandler.popupMessageBox(_myStrings.MsgAucIOffer(int(auctionDialog.Data)), null);
			}
			
		/* @TODO - full play options dialog AFTER Move (throw dies flow) */
		// flow diagram #3
		private function playerDialogAfterDies(field:Field):void 
			{
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("[GameController][onStatusRespond][CMD.STATUS_DIES][playerDialogAfterDies] Sent done_move. now bringing up AfterDies dialog...\n Field property type: " + field.PropertyType);
			
			/* action per property type */
			
			if (Field.TYPE_QUEST == field.PropertyType)
				{
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
					trace("[GameController][PlayerDialogAfterDies][Field.TYPE_QUEST]");
				}
			else if (Field.TYPE_PROPERTY == field.PropertyType)
				{
				if (Field.NO_OWNER == field.Status) // Bank dialog - Diagram 6
					{
					if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
						trace("[GameController][PlayerDialogAfterDies][Field.NO_OWNER] buy from Bank");
					var bankDialog:BankDialog = new BankDialog(_MyPlayer, field);
					bankDialog.addEventListener(Event.COMPLETE, onBankDialogComplete);
					bankDialog.name = VPanel.RPANEL_MIDDLE;
					_VPanel.addChild(bankDialog);
					}
				else if (Field.HAS_OWNER == field.Status)
					{
					if (field.Owner == _MyPlayer)
						{
						if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][PlayerDialogAfterDies][Field.HAS_OWNER] I am the Owner");
						end_turn(); // we might wanna change that to load the "Properties dialog" !
						}
					else
						{
						if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][PlayerDialogAfterDies][Field.HAS_OWNER] I am NOT the Owner");
						if (_MyPlayer.Cash >= field.Fee) 	// owned by other player flow - Diagram 4
							{
							if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
								trace("[GameController][PlayerDialogAfterDies][Field.HAS_OWNER] I am NOT the Owner, but I have the money!");
							ac_pay(field);
							}
						else	// must mortgage or go bankrupt
							{
							/* check if bankrupt */
							
							if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
								trace("[GameController][PlayerDialogAfterDies][Field.HAS_OWNER] I am NOT the Owner, and I do Not have the money!");
							
							var player_fields:Array = playerFields(field.Owner);
							var sum:int = 0;
							
							for each (var fieldItem:Field in player_fields)
								{
								sum = sum + fieldItem.Cost // don't need all the rest! Server updates client with LAST cost !!! + (fieldItem.UpgradeLevel * fieldItem.Cost * 0.4);		//TODO - Synch with Igor about upgrade real math...
								if (sum > field.Fee)
									{
									mortgageDialog(player_fields, field);		// not bankrupt
									break;
									}
								}
							if (sum < field.Fee)
								{
								//TODO - bankrupt!! GAME OVER - DISCONNECT
								var gmOver:String = _myStrings.MsgGameOver;
								_PopupMessageHandler.Timeout = 3000;
								_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
								_PopupMessageHandler.popupMessageBox(gmOver, null);
								_NetAgentCMDs.CMDdisconnect();
								}
							}
						}
					}
				else if (Field.MORTGAGED == field.Status)
					{
					if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
						trace("[GameController][PlayerDialogAfterDies][Field.MORTGAGED]");
					end_turn();
					}
				else
					{
					if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
						trace("[GameController][PlayerDialogAfterDies][Field.OWNER] ERROR!! Field Owner NOT detected. Field Status= " + field.Status);
					}
				}
			else if (Field.TYPE_OTHER == field.PropertyType)
				{
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
					trace("[GameController][PlayerDialogAfterDies][Field.TYPE_OTHER]");
				}
			else
				{
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
					trace("[GameController][PlayerDialogAfterDies][Field.TYPE] ERROR: Field type NOT detected!! ");
				}
			}
		
		private function ac_pay(field:Field):void
			{
			_NetAgentCMDs.ac_pay(field.Owner.ID, field.PropertyID, field.Fee);
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("[GameController][PlayerDialogAfterDies][Field.HAS_OWNER][ac_pay]");
			}
		private function negotiate(field:Field):void
			{
			var msgstr:String = _myStrings.MsgPayOwner(field.Fee, field.Owner.Name);
			
			_ShallPopDown = false;
			_PopupMessageHandler.Timeout = 3000;
			_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
			_PopupMessageHandler.popupMessageBox(msgstr, negotiateDialog, field);
			}
			
		/* server/other-player response to client Action commands handler (4xx) */
		
		private function onClientActionResponse(cmdRes:CMDResponse):void
			{
			var contentBA:ByteArray = cmdRes.Content as ByteArray;

			_PopupMessageHandler.popdownMessageBox();
			
			/* analyze server response */
			
			var Result:int	= contentBA.readInt();
			
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("[GameController][onClientActionResponse]	Result is: " + Result);
			
			var field:Field;
			if (CMD.DONE_MOVE == cmdRes.Command)
				{
				/* choose correct dialog based on game flow charts */
				
				field = getFieldbyID(_MyPlayer.CurrentPosition);
				playerDialogAfterDies(field);
				}
			//			[C1]    490 - ACTION_AUCTION - content size is 4*2 (2 ints)
			//                Structure: 490|fieldID|SumOfDeal (minimum)
			//[S-(C*-C1)]                690|fieldID|SumOfDeal (Round-Rubin, not broadcast!)
			//Loop (until everyone but one Pass, But up to three times - the best offer wins):
			//  [C2..n(round) -S]      690|fieldID|Offering || Pass| (0 = Pass)
			//  [S-C*]                        690|fieldID|DealPartnerID(CID)|OfferingSum || Pass (Broadcast!)
			//End Loop
			//[S-C*]                          490|fieldID|[WinnerID(CID)|SumOffered] || Pass (no one wants to buy, get lost ;-) ) (Broadcast !!)
			else if (CMD.ACTION_AUCTION == cmdRes.Command)
				{
				// "Result" is actually first field of the content which is a property
				field				= getFieldbyID(Result);
				var winnerID:int	= contentBA.readInt();
				var sum:int 		= 0;
				var winOrPassStr:String = _myStrings.MsgAucEveryonePass;
				
				// there is a winner
				if (winnerID != 0)
					{
					sum = contentBA.readInt();
					winOrPassStr = _myStrings.MsgAucSuccess(SelectPlayerByID(winnerID).Name, field.PropertyName, sum);
					}
								
				_ShallPopDown = false;

				_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
				_PopupMessageHandler.Timeout = 2000;
				
				_PopupMessageHandler.popupMessageBox(winOrPassStr, (_MyPlayer == field.Owner) ? end_turn : null);				
				}
			else if (CMD.ACTION_RES_DEAL == Result)
				{
				switch (cmdRes.Command)
					{
					case (CMD.ACTION_PAY)	   :
						_GameActionSound.play();
						field = getFieldbyID(_MyPlayer.CurrentPosition);
						negotiate(field);
						break;
					case (CMD.ACTION_BUY)      :	// this could only happen After Negotiation dialog which is After ThrowDies flow
						// show msg box about success deal
						_PopupMessageHandler.Timeout = 2000;
						_ShallPopDown = false;
						_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
						_PopupMessageHandler.popupMessageBox(_myStrings.MsgPurchaseSuccess, end_turn);
						_GameActionSound.play();
						break;
					case (CMD.ACTION_SELL)	   :		// this one is an exception in the Flow, it can exist only if we allow property dilaog when player is on his own property
						_PopupMessageHandler.Timeout = 2500;
						_ShallPopDown = false;
						_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
						_PopupMessageHandler.popupMessageBox(_myStrings.MsgReqSuccess, playerDialogBeforeDies, PlayDialog.TYPE_MOVE);
						_GameActionSound.play();
						break;
					case (CMD.ACTION_EXCHANGE) :	//TODO - 
						// need to think it over... probably previous dialog again
						break;
					case (CMD.ACTION_PARTNER)  :	//TODO -
						// need to think it over... probably previous dialog again
						break;
					case (CMD.ACTION_MORTGAGE) :
						_PopupMessageHandler.Timeout = 2000;
						_ShallPopDown = false;
						_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
						_PopupMessageHandler.popupMessageBox(_myStrings.MsgBankApproveReq, playerDialogBeforeDies, PlayDialog.TYPE_MOVE);
						_GameActionSound.play();
						break;
					case (CMD.ACTION_UPGRADE)  :
						_PopupMessageHandler.Timeout = 2000;
						_ShallPopDown = false;
						_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
						_PopupMessageHandler.popupMessageBox(_myStrings.MsgUpgSuccess, pre_dies_property_actions_dialog);
						break;
					}
				}
			else if (CMD.ACTION_RES_REJ == Result)
				{
				/* for debug only... */
				_PopupMessageHandler.Timeout = 2000;
				_PopupMessageHandler.addEventListener(TimerEvent.TIMER, popup_timerHandler);
				/* for debug only - end */
				switch (cmdRes.Command)
					{
					case (CMD.ACTION_BUY)      :	
						// need to think it over... probably previous dialog again
						_PopupMessageHandler.popupMessageBox(_myStrings.MsgBuyReject, playerDialogBeforeDies, PlayDialog.TYPE_MOVE);
						break;
					case (CMD.ACTION_SELL)	   :		// this one is an exception in the Flow, it can exist only if we allow property dialog when player is on his own property
						// need to think it over... probably previous dialog again
						_PopupMessageHandler.popupMessageBox(_myStrings.MsgSellReject, playerDialogBeforeDies, PlayDialog.TYPE_MOVE);
						break;
					case (CMD.ACTION_EXCHANGE) :	//TODO - parse response content...
						// need to think it over... probably previous dialog again
						_PopupMessageHandler.popupMessageBox(_myStrings.MsgExchangeReject, playerDialogBeforeDies, PlayDialog.TYPE_MOVE);
						break;
					case (CMD.ACTION_PARTNER)  :	//TODO - parse response content...
						// need to think it over... probably previous dialog again
						_PopupMessageHandler.popupMessageBox(_myStrings.MsgPartnerReject, playerDialogBeforeDies, PlayDialog.TYPE_MOVE);
						break;
					case (CMD.ACTION_MORTGAGE) :
						break;
					case (CMD.ACTION_UPGRADE)  :
						_PopupMessageHandler.Timeout = 5500;
						_ShallPopDown = false;
						_PopupMessageHandler.popupMessageBox(_myStrings.MsgUpgError, pre_dies_property_actions_dialog);
						break;
					}
				}
			else	// future support
				{
				}
				
			}
			
		/* server/other-player Request (offer) to myPlayer commands handler (6xx) */
		
		private function onClientActionRequest(cmdRes:CMDResponse):void
			{
			var contentBA:ByteArray = cmdRes.Content as ByteArray;

			_PopupMessageHandler.popdownMessageBox();
			
			/* analyze server response */
			
			var fieldID:int 	= contentBA.readInt();
			
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("[GameController][onClientActionRequest]	fieldID is: " + fieldID);

			// server direct request for offer from this player (690)
			if (cmdRes.Command == CMD.ACTION_AUC_REQ)
				{
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][onClientActionRequest]	CMD is: ACTION_AUC_REQ (691)");
							
				var sum:int = contentBA.readInt();		// the minimum price or the last offer (of previous player)
				var auctionDialog:AuctionDialog = new AuctionDialog(getFieldbyID(fieldID), AuctionDialog.STATUS_OFFER);
				auctionDialog.Data = sum;
				
				auctionDialog.addEventListener(MouseEvent.CLICK, auctionDialogComplete);
				auctionDialog.name = VPanel.RPANEL_MIDDLE;
				_VPanel.addChild(auctionDialog as Sprite);
				}
			else
				{
				var partnerID:int	= contentBA.readInt();
				if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
					trace("[GameController][onClientActionRequest]	partnerID is: " + partnerID);
	
				var dialog:BasicDialog;
				var sumOfDeal:int;
				switch (cmdRes.Command)
					{
					// server Broadcast to all players about any player offering (691)
					case (CMD.ACTION_AUC_RESP) :
						if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][onClientActionRequest]	CMD is: ACTION_AUC_RESP (690)");

						_ShallPopDown = true;
						
						sumOfDeal = contentBA.readInt();
						// 0 = Pass
						if (sumOfDeal == 0)
							_PopupMessageHandler.popupMessageBox(_myStrings.MsgAucPlayerPass(SelectPlayerByID(partnerID).Name), null);
						else
							_PopupMessageHandler.popupMessageBox(_myStrings.MsgAucPlayerOffer(SelectPlayerByID(partnerID).Name, sumOfDeal), null);
						break;
					case (CMD.ACTION_BUY_RESP) :	
						// 600|fieldId|DealPartnerID(CID)|SumOfDeal
						if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][onClientActionRequest]	CMD is: ACTION_BUY_RESPONSE");
						sumOfDeal = contentBA.readInt();
						if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][onClientActionRequest]	Sum of Deal is: " + sumOfDeal);
						//TODO - PlayerResponse dialog
						dialog = new BasicDialog(_myStrings.MsgAcceptRejectTitle, 
												   _myStrings.MsgBuyOffer(SelectPlayerByID(partnerID).Name, getFieldbyID(fieldID).PropertyName),
												   _myStrings.MsgAccept, _myStrings.MsgReject);
						dialog.store_data(CMD.ACTION_BUY_RESP);
						dialog.addEventListener(MouseEvent.CLICK, onActionRequestAcceptReject);
						dialog.name = VPanel.RPANEL_MIDDLE;
						_VPanel.addChild(dialog);
						break;
					case (CMD.ACTION_EXC_RESP) :	//TODO - parse response content...
						// 610|fieldId|DealPartnerID(CID)|otherFieldId
						if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][onClientActionRequest]	CMD is: ACTION_EXCHANGE_RESPONSE");
						var offeredField:int = contentBA.readInt();
						if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][onClientActionRequest]	Offered field ID is: " + offeredField);
						dialog = new BasicDialog(_myStrings.MsgAcceptRejectTitle, 
												   _myStrings.MsgExchangeOffer(SelectPlayerByID(partnerID).Name, getFieldbyID(fieldID).PropertyName),
												   _myStrings.MsgAccept, _myStrings.MsgReject);
						dialog.store_data(CMD.ACTION_EXC_RESP);
						dialog.addEventListener(MouseEvent.CLICK, onActionRequestAcceptReject);
						dialog.name = VPanel.RPANEL_MIDDLE;
						_VPanel.addChild(dialog);
						break;
					case (CMD.ACTION_PAR_RESP)  :	//TODO - parse response content...
						// 620|fieldId|DealPartnerID(CID)|%
						break;
					case (CMD.ACTION_SEL_RESP)  :
						// 630|fieldId|DealPartnerID(CID)|SumOfDeal
						if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][onClientActionRequest]	CMD is: ACTION_SELL_RESPONSE");
						sumOfDeal = contentBA.readInt();
						if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
							trace("[GameController][onClientActionRequest]	Sum of Deal is: " + sumOfDeal);
						dialog = new BasicDialog(_myStrings.MsgAcceptRejectTitle, 
												   _myStrings.MsgSellOffer(SelectPlayerByID(partnerID).Name, getFieldbyID(fieldID).PropertyName),
												   _myStrings.MsgAccept, _myStrings.MsgReject);
						dialog.store_data(CMD.ACTION_SEL_RESP);
						dialog.addEventListener(MouseEvent.CLICK, onActionRequestAcceptReject);
						dialog.name = VPanel.RPANEL_MIDDLE;
						_VPanel.addChild(dialog);
						break;
					}
				}
			}
		private function onActionRequestAcceptReject(e:MouseEvent):void
			{
			if (e.target is Button)
				{
				var dialog_type:int = ((e.currentTarget as BasicDialog).retrieve_data() as int);
				var result:Boolean = false;
				
				if ( (e.target as Button).label == _myStrings.MsgAccept )
					{
					result = true;
					}
				else if ( (e.target as Button).label == _myStrings.MsgReject )
					{
					result = false;
					}
					
				switch (dialog_type)
					{
					case (CMD.ACTION_BUY_RESP) :
						_NetAgentCMDs.ac_req_buy((result) ? 0 : 1);
					case (CMD.ACTION_EXC_RESP) :
						_NetAgentCMDs.ac_req_exchange((result) ? 0 : 1);
					case (CMD.ACTION_PAR_RESP) :
						_NetAgentCMDs.ac_req_partner((result) ? 0 : 1);
					case (CMD.ACTION_SEL_RESP) :
						_NetAgentCMDs.ac_req_sell((result) ? 0 : 1);
					}

				e.currentTarget.removeEventListener(MouseEvent.CLICK, onActionRequestAcceptReject);
				_VPanel.removeChild(e.currentTarget as Sprite);
				}
			}
		
		private function mortgageDialog(playerFields:Array, field:Field):void
			{
			var mortgageDialog:MortgageDialog = new MortgageDialog(playerFields, field);
			mortgageDialog.addEventListener(Event.COMPLETE, onMortgageDialogComplete);
			mortgageDialog.name = VPanel.RPANEL_MIDDLE;
			_VPanel.addChild(mortgageDialog);
			}
		private function onMortgageDialogComplete(e:Event):void
			{
			var mortgageDialog:MortgageDialog =e.currentTarget as MortgageDialog;
			_NetAgentCMDs.ac_mortgage(_MyPlayer.ID, mortgageDialog.ChosenFields, mortgageDialog.Sum);
			
			/* now can go back to Player-Negotiate Dialog */
			
			negotiate(mortgageDialog.StoredData as Field);
			}
			
		private function negotiateDialog(field:Field):void
			{
			var playerNegotiateDialog:PlayerNegotiate = new PlayerNegotiate(field);
			playerNegotiateDialog.addEventListener(Event.COMPLETE, onPlayerNegotiateComplete);
			playerNegotiateDialog.name = VPanel.RPANEL_MIDDLE;
			_VPanel.addChild(playerNegotiateDialog);
			}

		private function onBankDialogComplete(e:Event):void
			{
			var bankDialog:BankDialog = e.currentTarget as BankDialog;
			
			switch (bankDialog.chosenAction)
				{
				case (BankDialog.ACTION_PASS) :
					end_turn();
					break;
				case (BankDialog.ACTION_BUY)  :
					_NetAgentCMDs.ac_buy(BankPlayer.BANK_ID, bankDialog.field.PropertyID, bankDialog.field.Cost);
					_PopupMessageHandler.popupMessageBox(_myStrings.MsgBankBuyProperty(bankDialog.field.PropertyName, bankDialog.field.Cost), null);
					//end_turn();
					break;
				}
				
			e.currentTarget.removeEventListener(Event.COMPLETE, onBankDialogComplete);
			_VPanel.removeChild(e.currentTarget as Sprite);
			}
			
		private function onPlayerNegotiateComplete(e:Event):void
			{
			var playerNegotiate:PlayerNegotiate = e.currentTarget as PlayerNegotiate;
			
			switch (playerNegotiate.chosenAction)
				{
				case (PlayerNegotiate.ACTION_PARTNER)  :			//TODO - in phase II, Tentative if this feature is really required (to be implemented inside Negotiate dialog)
					end_turn();  // for now, so game will not hang
					break;
				case (PlayerNegotiate.ACTION_EXCHANGE) :			//TODO - exchange property for property (to be implemented inside Negotiate dialog)
					end_turn();  // for now, so game will not hang
					break;
				case (PlayerNegotiate.ACTION_BUY)	   :			// Full Buy
					_PopupMessageHandler.popupMessageBox(_myStrings.MsgSellIOffer(playerNegotiate.field.PropertyName, playerNegotiate.field.Owner.Name, playerNegotiate.field.Cost), null);
					_NetAgentCMDs.ac_buy(playerNegotiate.field.Owner.ID, playerNegotiate.field.PropertyID, playerNegotiate.field.Cost);		// wait for server reponse to continue action.
					break;																												// not ending turn at this point
				case (PlayerNegotiate.ACTION_PASS):
					end_turn();
					break;
				}
				
			e.currentTarget.removeEventListener(Event.COMPLETE, onPlayerNegotiateComplete);
			_VPanel.removeChild(e.currentTarget as Sprite);
			}
		
		/* end turn function */
		
		private function end_turn():void
			{
			var rbuttons:Array = new Array();
			rbuttons.push(_myStrings.MsgEndTurnTitle);
			
			var PlayerDecisionDlg:RadiosDialog = new RadiosDialog(_myStrings.MsgEndTurnTitle, 
						 _myStrings.MsgEndTurnText, rbuttons);
			PlayerDecisionDlg.addEventListener(MouseEvent.CLICK, onPlayerEndTurnClick);
			PlayerDecisionDlg.name = VPanel.RPANEL_MIDDLE;
			_VPanel.addChild(PlayerDecisionDlg);
			}
		
		// on end turn
		private function onPlayerEndTurnClick(e:MouseEvent):void
			{
			if (e.target as Button)
				{
				var PlayerDecisionDlg:RadiosDialog = e.currentTarget as RadiosDialog;
				if (BasicDialog.NO_CHOICE == PlayerDecisionDlg.ChosenOption)
					return;
				e.currentTarget.removeEventListener(MouseEvent.CLICK, onPlayerEndTurnClick);
				e.currentTarget.remove( );
				_VPanel.removeChild(Sprite(e.currentTarget));
				
				_NetAgentCMDs.end_turn();
				}
			}
		
		/* common message box pop-up functions */
		
		private function popup_timerHandler(event:TimerEvent):void
			{
			event.currentTarget.removeEventListener(TimerEvent.TIMER, popup_timerHandler);			
			
			_PopupMessageHandler.popdownMessageBox();
			
			var func:Function = _PopupMessageHandler.ProcessFunc;
			(null != func) ? func.apply(this, _PopupMessageHandler.Args) : 0;
			}
			
		private function onResign(e:Event):void
			{
			if (_Resign.chosenAction == ResignView.RESIGN)
				{
				_MyPlayer.Active = false;
				_Players.removePlayer(_MyPlayer);

				var dO:DisplayObject = _VPanel.getChildByName(VPanel.RPANEL_MIDDLE);
				trace("[GameController][onResign] detected child: " + dO);
				(null != dO) ? _VPanel.removeChild(dO) : 0;

				for (var i:int = 0; i < _PlayersViews.length; i++)
					{
					if (_MyPlayer == _PlayersViews[i].Data)
						Sprite(_GameBoardViews.getChildAt(0)).removeChild(_PlayersViews[i]);
					}
				_NetAgentCMDs.ac_resign();
				}
			}
			
		/* Model management functions */
		
		private function playerFields(player:Player):Array
			{
			var board:GameBoard 	= _GameBoards.ActiveBoard;
			var FieldIter:IIterator = board.iterator();
			var field:Field;

			var playerFields:Array = new Array( );
			
			for each (field in FieldIter)
				{
				if (player == field.Owner)
					{
					playerFields.push(field);
					}
				}
			return playerFields;
			}
			
		private function SelectPlayerByID(playerID:int):Player
			{
			var playerIter:IIterator = _Players.iterator();
//@TP - add feature - player creation triggered by Server STATUS command - BEGIN
			var player:Player = null;
			var foundFlag:Boolean = false;
			
			for (var i:int = 0; playerIter.hasNext() && (player = Player(playerIter.next())); i++)
				{
				if (player.ID == playerID)
					{
					foundFlag = true;
					break;
					}
				}
			
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				{
				trace("[GameController][SelectPlayerByID] Selected Player by ID (from server) was: " + playerID);
				trace("[GameController][SelectPlayerByID] User found: " + foundFlag);
				}
			
			return (foundFlag ? player : null);
//@TP - add feature - player creation triggered by Server STATUS command - END
			}

		private function getFieldbyID(ID:uint):Field
			{
			var board:GameBoard;
			var FieldIterator:IIterator;
			var field:Field = null;
			
			board 		  = _GameBoards.ActiveBoard;
			FieldIterator = board.iterator();

			while (FieldIterator.hasNext())
				{
				field = FieldIterator.next() as Field;
				
				if (field.PropertyID == ID)
					break;
				}
			
			return field;
			}
		private function getFieldbyPosition(Position:uint):Field
			{
			var board:GameBoard;
			var FieldIterator:IIterator;
			var field:Field = null;
			
			board 		  = _GameBoards.ActiveBoard;
			FieldIterator = board.iterator();

			while (FieldIterator.hasNext())
				{
				field = FieldIterator.next() as Field;
				
				if (field.Position == Position)
					break;
				}
			
			return field;
			}
		
		/* this function returns true if Specific group of fields is owned by the player */
		// suitable for Phase-1, when only Current field (player position) might be upgraded if belong to group owned by player
		private function playerHasFullFieldGroup(player:Player):Boolean
			{
			var board:GameBoard = _GameBoards.ActiveBoard;
			var ret:Boolean = true;
			var group:uint = getFieldbyPosition(player.CurrentPosition-1).Group;
			
			var fields:Array = board.getFieldsByGroup(group);
			
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("[GameController][playerHasFullFieldGroup] group found for player is: " + group);
				
			for (var i:int = 0; i < fields.length; i++)
				{
				if (fields[i].Owner != player)
					{
					ret = false;
					break;
					}
				}
			if (GLOBALS.DEBUG & GLOBALS.DEBUG_LOGIC)
				trace("[GameController][playerHasFullFieldGroup] return: " + ret);
			return ret;
			}
		
		/* this function returns true if ANY of the field groups is owned by the player */
		// suitable for Phase-2, when All fields owned by player might be upgraded
		private function playerHasFullFieldGroups(player:Player):Boolean
			{
			var board:GameBoard = _GameBoards.ActiveBoard;
			var ret:Boolean		= false;
			var found:Boolean	= false;
			
			for each (var group in board.FieldGroups)
				{
				var fields:Array = board.getFieldsByGroup(group);
				
				for (var i:int = 0; i < fields.length; i++)
					{
					if (fields[i].Owner != player)
						break;
					else if (i == fields.length - 1)
						found = true;
					}
				if (found == true)
					{
					ret = true;
					break;
					}
				}
			return ret;
			}
		
			
// following is the legacy Math based function for moving player view over Multiple boards. now we use DB cordinates on One board...			
//		private function UpdatePlayerPosition(player:Player):void
//			{
			/* locate relevant Field - to adjust Player position */
				
//			var board:GameBoard;		 //= _GameBoards.ActiveBoard;
//			var FieldIterator:IIterator; //= board.iterator();
//			var field:Field;
			
			/* simple math for: on which board is player now? */
			
//			var tmpIndex:int   = Math.ceil(player.CurrentPosition / NUM_OF_FIELDS) - 1; // shift left due to board array start from Zero
//			var boardIndex:int = (tmpIndex < 0) ? 0 : tmpIndex;
			
//			var RelativePosition:uint = player.CurrentPosition % NUM_OF_FIELDS;
			
			/* the actual move */
			
//			if (_GameBoards.SetActiveBoard(boardIndex) != true)
//				{
//				trace("Error switching Active Board");
//				return;
//				}
			
			/* move playerView to correct BoardView */
			
//			Sprite(_GameBoardViews.getChildAt(0)).addChild(_PlayersViews[player.ID-1]);

			
			//the other way:
			//var boardView:GameBoardView;
			//var boardviewIter:IIterator = _GameBoardViews.iterator();
			
			//for (var j:uint = 0; boardviewIter.hasNext() && (boardView = GameBoardView(boardviewIter.next())); j++)
			//	{
			//	if (j == _GameBoards.ActiveBoardIndex)
			//		boardView.addChild(_PlayersViews[player.ID-1]);
			//	}
			
			// move player view to new field
//			board 		  = _GameBoards.ActiveBoard;
//			FieldIterator = board.iterator();
			
//			for (var i:uint = 0; FieldIterator.hasNext() && (field = Field(FieldIterator.next())); i++)
//				{
//				if (i == RelativePosition)
//					{
//					player.set_XY(field.X+player.ID*15, field.Y);
//					trace("Player X: " + player.X + ", Player Y: " + player.Y);
//					break;
//					}
//				}
//			}
		}
}